/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package co.edu.unal.bioingenium.kbmed.knowledge.dao;

import co.edu.unal.bioingenium.kbmed.config.Configuration;
import co.edu.unal.bioingenium.kbmed.knowledge.vo.Concept;
import co.edu.unal.bioingenium.kbmed.knowledge.vo.Relationship;
import co.edu.unal.bioingenium.kbmed.knowledge.vo.Descriptor;
import co.edu.unal.bioingenium.kbmed.knowledge.vo.DescriptorData;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Alejandro Riveros Cruz Riveros Cruz
 */
public abstract class KnowledgeSourceDAO {

    /**
     * Object that represent the connection to a database
     */
    protected Connection connection;
    /**
     * Object to perform querys over a database
     */
    protected Statement statement;
    /**
     * The field separator
     */
    public static final String FIELD_SEPARATOR = "::";

    /**
     * Default constructor
     */
    public KnowledgeSourceDAO() {
        connect();
    }

    /**
     *  Method to make the connection to database
     */
    public void connect() {
        connect(Configuration.KNOWLEDGE_SOURCE_DB_SERVER_IP, Configuration.KNOWLEDGE_SOURCE_DB_NAME, Configuration.KNOWLEDGE_SOURCE_DB_USER, Configuration.KNOWLEDGE_SOURCE_DB_PASS);
    }

    /**
     * Method to make the connection to database
     */
    private void connect(String serverIp, String DBName, String userName, String password) {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://" + serverIp + ":3306/" + DBName, userName, password);
            statement = connection.createStatement();
            initStatements();
        } catch (ClassNotFoundException cnfe) {
            System.out.println("Could not find the database driver");
            Logger.getLogger(KnowledgeSourceDAO.class.getName()).log(Level.SEVERE, null, cnfe);
        } catch (SQLException sqle) {
            System.out.println("Could not connect to the Snomed database");
            Logger.getLogger(KnowledgeSourceDAO.class.getName()).log(Level.SEVERE, null, sqle);
        }
    }

    /**
     * 
     * @return
     */
    public boolean isClosed() {
        try {
            return connection.isClosed();
        } catch (SQLException ex) {
            Logger.getLogger(KnowledgeSourceDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return true;
    }

    /**
     * 
     */
    public void checkStatus() {
        if (isClosed()) {
            connect();
        }
    }

    /**
     * Methdo to disconnect froma  database
     */
    public void close() {
        try {
            statement.close();
            connection.close();
        } catch (SQLException sqle) {
            Logger.getLogger(KnowledgeSourceDAO.class.getName()).log(Level.SEVERE, null, sqle);
        }
    }

    /**
     * Method to do a query over a database
     * @param: String the query to perform
     * @return 
     * @return: Resulset the result of the query
     * @param query 
     */
    public ResultSet doQuery(String query) {
        ResultSet resulset = null;
        try {
            statement.executeQuery(query);
            resulset = statement.getResultSet();
        } catch (SQLException sqle) {
            System.out.println("Error on execute query " + query);
            Logger.getLogger(KnowledgeSourceDAO.class.getName()).log(Level.SEVERE, null, sqle);
        }
        return resulset;
    }

    /**
     * Method to do an insertion over a database
     * @param: String the insertion sql sentence
     * @param query 
     */
    public void doInsert(String query) {
        try {
            statement.executeUpdate(query);
        } catch (SQLException sqle) {
            System.out.println("Error on execute insert " + query);
            Logger.getLogger(KnowledgeSourceDAO.class.getName()).log(Level.SEVERE, null, sqle);
        }
    }

    /**
     * This method is used to init the prepare statements to perform querys over the database
     * @throws SQLException 
     */
    public abstract void initStatements() throws SQLException;

    //Methods related with concepts
    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Set<String> getConceptsIds();

    /**
     * @param:
     * @return 
     * @return:
     * @param criteria 
     */
    public abstract Set<String> getConceptsIds(Map<String, String> criteria);

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Set<Concept> getConcepts();

    /**
     * @param:
     * @return:
     * @return 
     * @param criteria 
     */
    public abstract Set<Concept> getConcepts(Map<String, String> criteria);

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, Concept> getConceptbyConceptId();

    //Methods related to terms and descriptors linked to concepts
    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, Set<String>> getTermsByConceptId();

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, String> getTermsByDescriptorId();

    /**
     * @param:
     * @return:
     * @return 
     * @param descriptorId 
     */
    public abstract String getTermForDescriptorId(String descriptorId);

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, String> getConceptIdByDescriptorId();

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, Set<Descriptor>> getDescriptorsByConceptId();

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, Set<String>> getDescriptorsIdsByConceptId();

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, Descriptor> getDescriptorsByDescriptorId();

    /**
     * @param:
     * @return 
     * @return:
     * @param conceptID 
     */
    public abstract Map<String, String> getTermsForConcept(String conceptID);

    //Methods related to relationsips between concepts
    /**
     * @param:
     * @return:
     * @return 
     * @param concept2ID 
     */
    public abstract Set<String> getRelatedConcepts_1TO2(String concept2ID);

    /**
     * @param:
     * @param relationshipType 
     * @return 
     * @return:
     * @param concept2ID 
     */
    public abstract Set<String> getRelatedConcepts_1TO2(String concept2ID, String relationshipType);

    /**
     * @param:
     * @return:
     * @return 
     * @param concept1ID 
     */
    public abstract Set<String> getRelatedConcepts_2TO1(String concept1ID);

    /**
     * @param concept1ID 
     * @param:
     * @return 
     * @return:
     * @param relationshipType 
     */
    public abstract Set<String> getRelatedConcepts_2TO1(String concept1ID, String relationshipType);

    //Methods related to concepts category
    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Set<String> getCategories();

    /**
     * @param:
     * @return:List<String>
     * @return 
     * @param category 
     */
    public abstract Set<String> getConceptsInCategory(String category);

    /**
     * @param:
     * @return 
     * @return:
     * @param conceptId 
     */
    public abstract String getCategoryForConcept(String conceptId);

    /**
     * @param:
     * @return:
     * @return 
     * @param categoryId 
     */
    public abstract String getCategoryDescription(String categoryId);

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, String> getCategoryByConceptId();

    /**
     * @param:
     * @return:
     * @return 
     */
    public abstract Map<String, DescriptorData> getDescriptorDataByDescriptorId();
    //Insertion methods

    /**
     * @param:
     * @return:
     * @param concept 
     */
    public abstract void insertConcept(Concept concept);

    /**
     * @param:
     * @return:
     * @param relationship 
     */
    public abstract void insertRelationShip(Relationship relationship);

    /**
     * @param:
     * @return:
     * @param descriptor 
     */
    public abstract void insertDescriptor(Descriptor descriptor);
}
